
const { ccclass, property } = cc._decorator;


class TimerData {
    public callback: Function = null; // 触发的回调函数
    public interval: number = 0;      // 以秒为单位的时间间隔
    public repeat: number = 0;        // 重复次数
    public delay: number = 0;         // 第一次触延时时间

    public curCount: number = 0;      //记录当前次数, 区别延迟和间隔时间

    public timerId: number = 0;             // 标识定时器的唯一ID;
    public timerParam: any = null;          // 用户要传的参数
    public timerPassed: number = 0;         // 已过去时间统计
    public isRemoved: boolean = false;      // 是否已经删除
}

@ccclass
export default class TimerManage extends cc.Component {

    public static Instance: TimerManage = null;

    private m_autoTimerId: number = 0;
    private m_removeTimers: Array<TimerData> = [];
    private m_timersMap: Map<number, TimerData> = new Map();

    onLoad() {
        if (TimerManage.Instance == null) {
            TimerManage.Instance = this;
        }
        else {
            this.destroy();
            return;
        }
    }

    start() {
        this.m_removeTimers.length = 0;
        this.m_timersMap.clear();
    }

    protected update(dt: number): void {
        // 避免无效循环
        if (this.m_timersMap.size == 0) {
            return;
        }

        // 遍历timerMap进入定时环境内处理
        this.m_timersMap.forEach((value, key) => {
            let timerDatra = value;
            timerDatra.timerPassed += dt;
            if (timerDatra.timerPassed >= (timerDatra.curCount == 0 ? timerDatra.delay : timerDatra.interval)) {
                timerDatra.callback(timerDatra.timerParam);
                timerDatra.timerPassed -= (timerDatra.curCount == 0 ? timerDatra.delay : timerDatra.interval);
                timerDatra.delay = 0;
                if (timerDatra.repeat != cc.macro.REPEAT_FOREVER) {
                    timerDatra.repeat--;
                }
                timerDatra.curCount++;

                // 保持和cocos文档一致性，比如次数为3结果执行3+1次
                if (timerDatra.repeat < 0) {
                    timerDatra.isRemoved = true;
                    this.m_removeTimers.push(timerDatra);
                }
            }
        })

        // 删除完成的timers
        for (let i = 0, j = this.m_removeTimers.length; i < j; i++) {
            if (this.m_timersMap.has(this.m_removeTimers[i].timerId)) {
                this.m_timersMap.delete(this.m_removeTimers[i].timerId);
            }
        }
        this.m_removeTimers.length = 0;
    }

    private _scheduleWithParams(callback: Function, interval: number, repeat: number, delay: number, timerParam: any): number {
        let timerData: TimerData = new TimerData();
        timerData.callback = callback;
        timerData.interval = interval;
        timerData.repeat = repeat;
        timerData.delay = delay;

        timerData.curCount = 0;

        timerData.timerId = this.m_autoTimerId;
        timerData.timerParam = timerParam;
        timerData.timerPassed = 0;
        timerData.isRemoved = false;

        this.m_autoTimerId++;
        this.m_timersMap.set(timerData.timerId, timerData);

        return timerData.timerId;
    }

    /**
     * 和官方文档一直
     * @param callback  回调
     * @param interval  间隔时间 默认0
     * @param repeat    重复次数 n + 1次 默认无线循环 (cc.macro.REPEAT_FOREVER)
     * @param delay     延迟时间 默认0
     * @param param     参数传递 默认null
     * @returns 返回定时器唯一ID, 用于停止改ID对应的定时器
     */
    public schedule(callback: Function, interval: number = 0, repeat: number = cc.macro.REPEAT_FOREVER, delay: number = 0, param: any = null) {
        return this._scheduleWithParams(callback, interval, repeat, delay, param);
    }

    /**
     * 和官方文档一直
     * @param callback  回调
     * @param delay     延迟时间 默认0  
     * @param param     参数传递 默认null
     * @returns 返回定时器唯一ID, 用于停止改ID对应的定时器
     */
    public scheduleOnce(callback: Function, delay: number = 0, param: any = null) {
        return this._scheduleWithParams(callback, 0, 0, delay, param);
    }

    /**
     * 根据定时器唯一ID停止定时器
     * @param timerId 
     */
    public unSchedule(timerId: number) {
        let timerData = this.m_timersMap.get(timerId);
        if (timerData) {
            timerData.isRemoved = true;
            this.m_removeTimers.push(timerData);
        }
        else {
            console.warn('定时器唯一ID不存在')
        }
    }

    /**
     * 停止所有的定时器
     */
    public unScheduleAllCallbacks() {
        this.m_timersMap.forEach((value, key) => {
            value.isRemoved = true;
            this.m_removeTimers.push(value);
        })
    }

}
